Attribute VB_Name = "modSendCommand"
Option Explicit

Public Const USB_DiagDataDelayMS As Long = 2500&

Public Const DP4_PX4_OLD_CFG_SIZE = 64
Public Whitespace As String

Public Function DP5_CMD(ByRef Buffer() As Byte, XmtCmd As TRANSMIT_PACKET_TYPE) As Boolean
    Dim bCmdFound As Boolean
    Dim iFileNum As Integer
    Dim D As String
    Dim bt As Byte
    Dim idxData As Integer
    Dim idxMiscData As Integer
    Dim POUT As Packet_Out
    Dim lLen As Long
    Dim cstrCfg As String
    Dim strTemp As String
    
    bCmdFound = True
    POUT.LEN = 0

    Select Case XmtCmd
        ''REQUEST_PACKETS_TO_DP5
        Case XMTPT_SEND_STATUS
            POUT.PID1 = PID1_REQ_STATUS
            POUT.PID2 = PID2_SEND_STATUS
        'Case XMTPT_SEND_SPECTRUM
        'Case XMTPT_SEND_CLEAR_SPECTRUM
        Case XMTPT_SEND_SPECTRUM_STATUS
            POUT.PID1 = PID1_REQ_SPECTRUM
            POUT.PID2 = PID2_SEND_SPECTRUM_STATUS   ' send spectrum & status
        Case XMTPT_SEND_CLEAR_SPECTRUM_STATUS
            POUT.PID1 = PID1_REQ_SPECTRUM
            POUT.PID2 = PID2_SEND_CLEAR_SPECTRUM_STATUS   ' send & clear spectrum & status
        'Case XMTPT_BUFFER_SPECTRUM
        'Case XMTPT_BUFFER_CLEAR_SPECTRUM
        'Case XMTPT_SEND_BUFFER
        'Case XMTPT_SEND_CONFIG
        Case XMTPT_SEND_SCOPE_DATA
            POUT.PID1 = PID1_REQ_SCOPE_MISC
            POUT.PID2 = PID2_SEND_SCOPE_DATA
        Case XMTPT_SEND_512_BYTE_MISC_DATA
            POUT.PID1 = PID1_REQ_SCOPE_MISC
            POUT.PID2 = PID2_SEND_512_BYTE_MISC_DATA ' request misc data
        'Case XMTPT_SEND_SCOPE_DATA_REARM
        'Case XMTPT_SEND_ETHERNET_SETTINGS
        Case XMTPT_SEND_DIAGNOSTIC_DATA
            POUT.PID1 = PID1_REQ_SCOPE_MISC
            POUT.PID2 = PID2_SEND_DIAGNOSTIC_DATA   ' Request Diagnostic Packet
            POUT.LEN = 0
        Case XMTPT_SEND_NETFINDER_PACKET
            POUT.PID1 = PID1_REQ_SCOPE_MISC
            POUT.PID2 = PID2_SEND_NETFINDER_READBACK   ' Request NetFinder Packet
            POUT.LEN = 0
        'Case XMTPT_SEND_HARDWARE_DESCRIPTION
        'Case XMTPT_SEND_SCA
        'Case XMTPT_LATCH_SEND_SCA
        'Case XMTPT_LATCH_CLEAR_SEND_SCA
        'Case XMTPT_SEND_ROI_OR_FIXED_BLOCK
        Case XMTPT_TEXT_CONFIGURATION_FILTERED      'FILTERS AND FIXES DPP TEXT COMMANDS
            cstrCfg = ""
            cstrCfg = HwCfgDP5Out

           
            cstrCfg = RemoveCmdByDeviceType(cstrCfg, STATUS.PC5_PRESENT, STATUS.DEVICE_ID, STATUS.isDP5_RevDxGains, STATUS.DPP_ECO)

            '''''==== remove whitespace ====================================================
            ''''lLen = Len(cstrCfg)
            ''''strTemp = cstrCfg
            ''''cstrCfg = ""
            ''''If (lLen > 0) Then
            ''''    For idxData = 1 To lLen
            ''''        If InStr(1, Whitespace, Mid(strTemp, idxData, 1)) = 0 Then
            ''''            cstrCfg = cstrCfg & Mid(strTemp, idxData, 1)  'append non-whitespace chars
            ''''        End If
            ''''    Next
            ''''End If
            '''''==== remove whitespace ====================================================
            
            lLen = Len(cstrCfg)
            If (lLen > 0) Then
                For idxData = 1 To lLen
                    POUT.Data(idxData - 1) = Asc(Mid(cstrCfg, idxData, 1))
                Next
            End If
            POUT.PID1 = PID1_REQ_CONFIG
            POUT.PID2 = PID2_TEXT_CONFIG_PACKET  ' text config packet
            POUT.LEN = lLen
        Case XMTPT_TEXT_CONFIGURATION           ' bypasses any filters, sends raw configuration
            cstrCfg = ""
            cstrCfg = HwCfgDP5Out
            lLen = Len(cstrCfg)
            If (lLen > 0) Then
                For idxData = 1 To lLen
                    POUT.Data(idxData - 1) = Asc(Mid(cstrCfg, idxData, 1))
                Next
            End If
            POUT.PID1 = PID1_REQ_CONFIG
            POUT.PID2 = PID2_TEXT_CONFIG_PACKET  ' text config packet
            POUT.LEN = lLen
         Case XMTPT_READ_TEXT_CONFIGURATION
            cstrCfg = ""
            cstrCfg = HwRdBkDP5Out
            lLen = Len(cstrCfg)
            If (lLen > 0) Then
                For idxData = 1 To lLen
                    POUT.Data(idxData - 1) = Asc(Mid(cstrCfg, idxData, 1))
                Next
            End If
            POUT.PID1 = PID1_REQ_CONFIG
            POUT.PID2 = PID2_CONFIG_READBACK_PACKET   ' read config packet
            POUT.LEN = lLen
         Case XMTPT_FULL_READ_TEXT_CONFIGURATION
            cstrCfg = ""
            cstrCfg = CreateFullReadBackCmd()

            lLen = Len(cstrCfg)
            If (lLen > 0) Then
                For idxData = 1 To lLen
                    POUT.Data(idxData - 1) = Asc(Mid(cstrCfg, idxData, 1))
                Next
            End If
            POUT.PID1 = PID1_REQ_CONFIG
            POUT.PID2 = PID2_CONFIG_READBACK_PACKET   ' read config packet
            POUT.LEN = lLen
        Case XMTPT_ERASE_FPGA_IMAGE
            POUT.PID1 = PID1_REQ_FPGA_UC
            POUT.PID2 = PID2_ERASE_FPGA_IMAGE
            POUT.LEN = 2
            POUT.Data(0) = &H12
            POUT.Data(1) = &H34
        'Case XMTPT_UPLOAD_PACKET_FPGA
        'Case XMTPT_REINITIALIZE_FPGA
        'Case XMTPT_ERASE_UC_IMAGE_0
        Case XMTPT_ERASE_UC_IMAGE_1
            POUT.PID1 = PID1_REQ_FPGA_UC
            POUT.PID2 = PID2_ERASE_UC_IMAGE_1   ' erase image #1 (sector 5)
            POUT.LEN = 2
            POUT.Data(0) = &H12
            POUT.Data(1) = &H34
        
        'Case XMTPT_ERASE_UC_IMAGE_2
        'Case XMTPT_UPLOAD_PACKET_UC
        'Case XMTPT_SWITCH_TO_UC_IMAGE_0
        Case XMTPT_SWITCH_TO_UC_IMAGE_1
            POUT.PID1 = PID1_REQ_FPGA_UC
            POUT.PID2 = PID2_SWITCH_TO_UC_IMAGE_1   ' switch to uC image #1
            POUT.LEN = 2
            POUT.Data(0) = &HA5 ' uC FLASH unlock keys
            POUT.Data(1) = &HF1
        'Case XMTPT_SWITCH_TO_UC_IMAGE_2
        'Case XMTPT_UC_FPGA_CHECKSUMS

        ''VENDOR_REQUESTS_TO_DP5
        'Case XMTPT_CLEAR_SPECTRUM_BUFFER
        Case XMTPT_ENABLE_MCA_MCS
            POUT.PID1 = PID1_VENDOR_REQ
            POUT.PID2 = PID2_ENABLE_MCA_MCS
            POUT.LEN = 0
        Case XMTPT_DISABLE_MCA_MCS
            POUT.PID1 = PID1_VENDOR_REQ
            POUT.PID2 = PID2_DISABLE_MCA_MCS
            POUT.LEN = 0
        Case XMTPT_ARM_DIGITAL_OSCILLOSCOPE
            POUT.PID1 = PID1_VENDOR_REQ
            POUT.PID2 = PID2_ARM_DIGITAL_OSCILLOSCOPE   ' arm trigger
        'Case XMTPT_AUTOSET_INPUT_OFFSET
        'Case XMTPT_AUTOSET_FAST_THRESHOLD
        'Case XMTPT_READ_IO3_0
        'Case XMTPT_WRITE_IO3_0
        'Case XMTPT_SET_DCAL
        'Case XMTPT_SET_PZ_CORRECTION_UC_TEMP_CAL
        'Case XMTPT_SET_PZ_CORRECTION_UC_TEMP_CAL
        'Case XMTPT_SET_BOOT_FLAGS
        'Case XMTPT_SET_HV_DP4_EMULATION
        'Case XMTPT_SET_TEC_DP4_EMULATION
        'Case XMTPT_SET_INPUT_OFFSET_DP4_EMULATION
        'Case XMTPT_SET_ADC_CAL_GAIN_OFFSET
        'Case XMTPT_SET_SPECTRUM_OFFSET
        'Case XMTPT_REQ_SCOPE_DATA_MISC_DATA_SCA_PACKETS
        'Case XMTPT_SET_SERIAL_NUMBER
        'Case XMTPT_CLEAR_GP_COUNTER
        'Case XMTPT_SWITCH_SUPPLIES
        'Case XMTPT_SEND_TEST_PACKET
        
        '======================================================
        '==== REQUEST_PACKETS_TO_MX2 ==========================
        '======================================================
        Case XMTPT_SEND_TUBE_ILOCK_TABLE_MX2
            POUT.PID1 = PID1_REQ_SCOPE_MISC
            POUT.PID2 = PID2_SEND_MX2_TUBE_ILOCK_TABLE
            POUT.LEN = 0
        Case XMTPT_SEND_WARMUP_TABLE_MX2
            POUT.PID1 = PID1_REQ_SCOPE_MISC
            POUT.PID2 = PID2_SEND_MX2_WARMUP_TABLE
            POUT.LEN = 0
        Case XMTPT_SEND_TIMESTAMP_RECORD_MX2
            POUT.PID1 = PID1_REQ_SCOPE_MISC
            POUT.PID2 = PID2_SEND_MX2_TIMESTAMP_RECORD
            POUT.LEN = 0
        Case XMTPT_SEND_FAULT_RECORD_MX2
            POUT.PID1 = PID1_REQ_SCOPE_MISC
            POUT.PID2 = PID2_SEND_MX2_FAULT_RECORD
            POUT.LEN = 0
        
    '--------------------------------------------------------------
        Case XMTPT_WRITE_TIMESTAMP_MX2
            Dim datNow As Date
            datNow = Now

            POUT.PID1 = PID1_VENDOR_REQ
            POUT.PID2 = PID2_WRITE_MX2_TIMESTAMP        ' write MNX timestamp
            POUT.LEN = 6
            POUT.Data(0) = Month(datNow)                ' binary month
            POUT.Data(1) = Day(datNow)                  ' binary day
            POUT.Data(2) = CByte(Year(datNow) - 2000)   ' binary year, 2018=18
            POUT.Data(3) = Hour(datNow)                 ' binary hour
            POUT.Data(4) = Minute(datNow)               ' binary minutes
            POUT.Data(5) = Second(datNow)               ' binary seconds
    '----------------------------------------------------------------
        Case XMTPT_INITIATE_WARMUP_DAILY_SEQUENCE_MX2
            POUT.PID1 = PID1_VENDOR_REQ
            POUT.PID2 = PID2_INIT_MX2_WARMUP_SEQUENCE   ' Run warm-up sequence
            POUT.LEN = 1
            POUT.Data(0) = 0                            ' daily warm-up
        Case XMTPT_INITIATE_WARMUP_MONTHLY_SEQUENCE_MX2
            POUT.PID1 = PID1_VENDOR_REQ
            POUT.PID2 = PID2_INIT_MX2_WARMUP_SEQUENCE   ' Run warm-up sequence
            POUT.LEN = 1
            POUT.Data(0) = 1                            ' monthly warm-up
        Case Else
            bCmdFound = False
    End Select
    
    If bCmdFound Then
        If (Not POUT_Buffer(POUT, Buffer())) Then
            bCmdFound = False
        End If
    End If
    DP5_CMD = bCmdFound
End Function

Public Function DP5_CMD_Data(ByRef Buffer() As Byte, XmtCmd As TRANSMIT_PACKET_TYPE, DataOut As Variant) As Boolean
    Dim bCmdFound As Boolean
    Dim idxData As Integer
    Dim idxMiscData As Integer
    Dim POUT As Packet_Out
    Dim PktLen As Integer
    Dim strCfg As String
    Dim lLen As Long
    
    On Error GoTo DP5_CMD_DataErr
    
    bCmdFound = False
    POUT.LEN = 0
    Select Case XmtCmd
        Case XMTPT_WRITE_512_BYTE_MISC_DATA
            POUT.PID1 = PID1_VENDOR_REQ
            POUT.PID2 = PID2_WRITE_512_BYTE_MISC_DATA ' write misc data
            POUT.LEN = 512
            For idxMiscData = 0 To 511
                POUT.Data(idxMiscData) = Asc(Mid(DataOut + String(512, 0), idxMiscData + 1, 1))
            Next idxMiscData
            bCmdFound = True
            If (Not POUT_Buffer(POUT, Buffer())) Then
                bCmdFound = False
            End If
        Case XMTPT_SEND_TEST_PACKET
            If (Not IsMissing(DataOut)) Then
                PktLen = Len(DataOut)
                If (PktLen >= 8) Then
                    For idxData = 0 To PktLen - 1
                        Buffer(idxData) = CLng(DataOut(idxData))
                    Next
                    bCmdFound = True
                End If
            End If
        Case XMTPT_TEXT_CONFIGURATION_MX2           ' bypass any filters
            strCfg = ""
            strCfg = CStr(DataOut)
            lLen = Len(strCfg)
            If (lLen > 0) Then
                For idxData = 1 To lLen
                    POUT.Data(idxData - 1) = Asc(Mid(strCfg, idxData, 1))
                Next
                bCmdFound = True
                POUT.PID1 = PID1_REQ_CONFIG
                POUT.PID2 = PID2_TEXT_CONFIG_PACKET  ' text config packet
                POUT.LEN = lLen
                If (Not POUT_Buffer(POUT, Buffer())) Then
                    bCmdFound = False
                End If
            Else
                bCmdFound = False
            End If
         Case XMTPT_READ_TEXT_CONFIGURATION_MX2
            strCfg = ""
            strCfg = CStr(DataOut)
            lLen = Len(strCfg)
            If (lLen > 0) Then
                For idxData = 1 To lLen
                    POUT.Data(idxData - 1) = Asc(Mid(strCfg, idxData, 1))
                Next
                bCmdFound = True
                POUT.PID1 = PID1_REQ_CONFIG
                POUT.PID2 = PID2_CONFIG_READBACK_PACKET   ' read config packet
                POUT.LEN = lLen
                If (Not POUT_Buffer(POUT, Buffer())) Then
                    bCmdFound = False
                End If
            Else
                bCmdFound = False
            End If
        Case Else
            bCmdFound = False
    End Select
    DP5_CMD_Data = bCmdFound
    Exit Function
DP5_CMD_DataErr:
    bCmdFound = False
End Function

Public Function POUT_Buffer(POUT As Packet_Out, ByRef Buffer() As Byte) As Boolean
    Dim idxBuffer As Integer
    Dim CS As Long
    On Error GoTo POUT_BufferErr
    
    If (UBound(Buffer) < POUT.LEN + 7) Then ReDim Buffer(POUT.LEN + 7)
    Buffer(0) = SYNC1_
    Buffer(1) = SYNC2_
    Buffer(2) = POUT.PID1
    Buffer(3) = POUT.PID2
    Buffer(4) = (POUT.LEN And &HFF00) \ 256
    Buffer(5) = POUT.LEN And &HFF

    CS = SYNC1_ + SYNC2_ + POUT.PID1 + POUT.PID2 + (POUT.LEN And &HFF00) \ 256 + (POUT.LEN And &HFF)

    If POUT.LEN > 0 Then
        For idxBuffer = 0 To POUT.LEN - 1
            Buffer(idxBuffer + 6) = POUT.Data(idxBuffer)
            CS = CS + POUT.Data(idxBuffer)
        Next idxBuffer
    End If
    CS = (CS Xor &HFFFF&) + 1
    Buffer(POUT.LEN + 6) = (CS And &HFF00) \ 256
    Buffer(POUT.LEN + 7) = CS And &HFF
    POUT_Buffer = True
    Exit Function
POUT_BufferErr:
    POUT_Buffer = False
End Function

Public Function SendPacketUSB(DppWinUSB As WinUsbDevice, ByRef Buffer() As Byte, ByRef PacketIn() As Byte) As Boolean
    Dim bytesWritten As Long, bytesRead As Long
    Dim success As Boolean
    Dim strLog As String
    Dim i As Long
    Dim PLen As Long
    
    If ((Buffer(2) = PID1_REQ_SCOPE_MISC) And Buffer(3) = PID2_SEND_DIAGNOSTIC_DATA) Then
        ' Request Diagnostic Packet delay 'USB_DiagDataDelayMS
        Call SetPipePolicy1(DppWinUSB, CByte(DppWinUSB.bulkInPipe), CInt(PIPE_POLICY_TYPE.PIPE_TRANSFER_TIMEOUT), USB_DiagDataDelayMS)
        USB_Default_Timeout = False     ' flag that non-default timeout is in use
    Else
        If USB_Default_Timeout = False Then  ' change pipetimeout to default if it isn't already set that way
            Call SetPipePolicy1(DppWinUSB, CByte(DppWinUSB.bulkInPipe), CInt(PIPE_POLICY_TYPE.PIPE_TRANSFER_TIMEOUT), USB_TIMEOUT)
            USB_Default_Timeout = True     ' flag that default timeout is in use
        End If
    End If

    PLen = (Buffer(4) * 256) + Buffer(5) + 7

    ACK_Received = False
    Packet_Received = False ' a response packet is always expected
    PIN.STATUS = &HFF   ' packet invalid - will be overwritten soon by response/ACK packet

    success = WinUsb_WritePipe(DppWinUSB.winUsbHandle, CByte(DppWinUSB.bulkOutPipe), Buffer(0), PLen + 1, bytesWritten, 0&)
    success = VbBool(success)
    
    If (success) Then
        success = WinUsb_ReadPipe(DppWinUSB.winUsbHandle, CByte(DppWinUSB.bulkInPipe), PacketIn(0), 32767, bytesRead, 0&)
        strLog = strLog & "USB Req sent: PID1=" & Str(Buffer(2)) & ", PID2=" & Str(Buffer(3)) & ": OK" & vbCrLf
        success = VbBool(success)
        If (success) Then
            strLog = strLog & "USB Response: PID1=" & Str(PacketIn(2)) & ", PID2=" & Str(PacketIn(3)) & ": OK (read " & Str(bytesRead) & ")" & vbCrLf
            SendPacketUSB = True
        Else
            strLog = strLog & "USB Response: FAIL (read " & Str(bytesRead) & ")" & vbCrLf
            SendPacketUSB = False
        End If
    Else
       strLog = strLog & "USB Req sent: FAIL" & vbCrLf
       SendPacketUSB = False
    End If
End Function


